home *** CD-ROM | disk | FTP | other *** search
/ Programming Languages Suite / ProgramD2.iso / Borland / Borland C++ V5.02 / OWLSRC.PAK / LISTBOX.CPP < prev    next >
Encoding:
C/C++ Source or Header  |  1997-05-06  |  15.4 KB  |  606 lines

  1. //----------------------------------------------------------------------------
  2. // ObjectWindows
  3. // Copyright (c) 1991, 1997 by Borland International, All Rights Reserved
  4. //
  5. //$Revision:   10.8  $
  6. //
  7. // Implementation of class TListBox and TListBoxData.
  8. //----------------------------------------------------------------------------
  9. #pragma hdrignore SECTION
  10. #include <owl/pch.h>
  11. #if !defined(OWL_LISTBOX_H)
  12. # include <owl/listbox.h>
  13. #endif
  14. #include <stdlib.h>
  15.  
  16. OWL_DIAGINFO;
  17.  
  18. #if !defined(SECTION) || SECTION == 1
  19.  
  20. #define MULTIPLESEL    (LBS_MULTIPLESEL | LBS_EXTENDEDSEL)
  21.  
  22. //
  23. // TListBoxData constructor
  24. //
  25. TListBoxData::TListBoxData()
  26. :
  27.   Strings(10, 0, 10),
  28.   ItemDatas(10, 0, 10),
  29.   SelIndices(1, 0, 10)
  30. {
  31. }
  32.  
  33. //
  34. // TListBoxData destructor
  35. //
  36. TListBoxData::~TListBoxData()
  37. {
  38. }
  39.  
  40. //
  41. // Adds "str" to "Strings"
  42. //
  43. // If "isSelected" is true, marks it as selected
  44. //
  45. void
  46. TListBoxData::AddString(const char* str, bool isSelected)
  47. {
  48.   Strings.Add(str);
  49.   if (isSelected)
  50.     Select(Strings.GetItemsInContainer()-1);
  51. }
  52.  
  53. //
  54. // Adds str and associated item data to strings and datas
  55. //
  56. void
  57. TListBoxData::AddStringItem(const char* str, uint32 itemData, bool isSelected)
  58. {
  59.   ItemDatas.Add(itemData);
  60.   AddString(str, isSelected);
  61. }
  62.  
  63. //
  64. // Selects an item at a given index.
  65. //
  66. void
  67. TListBoxData::Select(int index)
  68. {
  69.   if (index != LB_ERR)
  70.     SelIndices.Add(index);
  71. }
  72.  
  73. //
  74. // Adds "str" to selection lists if it is in Strings
  75. //
  76. void
  77. TListBoxData::SelectString(const char far* str)
  78. {
  79.   for (uint i = 0; i < Strings.GetItemsInContainer(); i++)
  80.     if (strcmp(Strings[i].c_str(), str) == 0) {
  81.       Select(i);
  82.       break;
  83.     }
  84. }
  85.  
  86. //
  87. // Returns the length of the string at the passed selection index
  88. // excluding the terminating 0
  89. //
  90. int
  91. TListBoxData::GetSelStringLength(int index) const
  92. {
  93.   if (index >= 0 && index < GetSelCount())
  94.     return Strings[SelIndices[index]].length();
  95.   return -1;
  96. }
  97.  
  98. //
  99. // Copies the string at the passed selection index into buffer
  100. //
  101. // bufferSize includes the terminating 0
  102. //
  103. void
  104. TListBoxData::GetSelString(char far* buffer, int bufferSize, int index) const
  105. {
  106.   if (bufferSize > 0) {
  107.     if (index < 0 || index >= GetSelCount())
  108.       *buffer = 0;
  109.  
  110.     else {
  111.       strncpy(buffer, Strings[SelIndices[index]].c_str(), bufferSize-1);
  112.       buffer[bufferSize - 1] = 0;
  113.     }
  114.   }
  115. }
  116.  
  117. //
  118. // copies the string at the passed index in SelStrings into str
  119. //
  120. void
  121. TListBoxData::GetSelString(string& str, int index) const
  122. {
  123.   if (index >= 0 && index < GetSelCount())
  124.     str = Strings[SelIndices[index]];
  125.   else
  126.     str = "";
  127. }
  128.  
  129. //----------------------------------------------------------------------------
  130.  
  131. //
  132. // Constructor for TListBox
  133. //
  134. // Initializes its data fields using parameters passed and default values
  135. //
  136. // By default, a native listbox associated with the TListBox will:
  137. //   - be visible upon creation
  138. //   - have a border and a vertical scrollbar
  139. //   - maintain entries in alphabetical order
  140. //   - notify its parent when a selection is made
  141. //
  142. TListBox::TListBox(TWindow*   parent,
  143.                    int        id,
  144.                    int x, int y, int w, int h,
  145.                    TModule*   module)
  146. :
  147.   TControl(parent, id, 0, x, y, w, h, module)
  148. {
  149.   Attr.Style |= LBS_STANDARD;
  150. #if defined(BI_PLAT_WIN32)  
  151.   Attr.ExStyle |= WS_EX_CLIENTEDGE;  // Creates 3d sunken inside edge
  152. #endif
  153. }
  154.  
  155. //
  156. //
  157. //
  158. TListBox::TListBox(TWindow*   parent,
  159.                    int        resourceId,
  160.                    TModule*   module)
  161. :
  162.   TControl(parent, resourceId, module)
  163. {
  164. }
  165.  
  166. //
  167. //
  168. //
  169. char far*
  170. TListBox::GetClassName()
  171. {
  172.   return "LISTBOX";
  173. }
  174.  
  175. //
  176. // Transfers state information for a TListBox
  177. //
  178. // Transfers the items and selection of the list to or from a transfer
  179. // buffer if tdSetData or tdGetData, respectively, is passed as the
  180. // direction
  181. //
  182. // Buffer should point to a TListBoxData which points to the data to be
  183. // transferred
  184. //
  185. // Transfer returns the size of TListBoxData
  186. //
  187. // To retrieve the size without transferring data, pass tdSizeData as the
  188. // direction
  189. //
  190. uint
  191. TListBox::Transfer(void* buffer, TTransferDirection direction)
  192. {
  193.   long           style = GetStyle();
  194.   TListBoxData*  listBoxData = (TListBoxData*)buffer;
  195.  
  196.   if (direction == tdGetData) {
  197.  
  198.     // First, clear out Strings array and fill with contents of list box
  199.     //
  200.     listBoxData->Clear();
  201.  
  202.     // Pre-calculate max string length so that one big buffer can be used
  203.     //
  204.     int  count = GetCount();
  205.     int  maxStrLen = 0;
  206.     int  i;
  207.     for (i = 0; i < count; i++) {
  208.       int  strLen = GetStringLen(i);
  209.       if (strLen > maxStrLen)
  210.         maxStrLen = strLen;
  211.     }
  212.  
  213.     // Get each string and item data in the listbox & add to listboxdata
  214.     //
  215.     char*  tmpStr = new char[maxStrLen+1];
  216.     for (i = 0; i < GetCount(); i++) {
  217.       GetString(tmpStr, i);
  218.       listBoxData->AddStringItem(tmpStr, GetItemData(i), false);
  219.     }
  220.     delete[] tmpStr;
  221.  
  222.     // Update transfer data with new selected item(s)
  223.     //
  224.     listBoxData->ResetSelections();
  225.  
  226.     if (!(style & MULTIPLESEL)) {
  227.       // Single selection
  228.       //
  229.       listBoxData->Select(GetSelIndex());
  230.     }
  231.     else {
  232.       // Multiple selection
  233.       //
  234.       int  selCount = GetSelCount();
  235.       if (selCount > 0) {
  236.         int*  selections = new int[selCount];
  237.  
  238.         GetSelIndexes(selections, selCount);
  239.  
  240.         // Select each item by index
  241.         //
  242.         for (int selIndex = 0; selIndex < selCount; selIndex++)
  243.           listBoxData->Select(selections[selIndex]);
  244.  
  245.         delete[] selections;
  246.       }
  247.     }
  248.   }
  249.   else if (direction == tdSetData) {
  250.     ClearList();
  251.  
  252.     // Add each string, item data and selections in listBoxData to list box
  253.     //
  254.     const int noSelection = -1;
  255.     uint selCount = listBoxData->GetSelCount();  // for multi selection
  256.     int  selIndex = noSelection;                 // for single selection
  257.     for (uint i = 0; i < listBoxData->GetStrings().GetItemsInContainer(); i++) {
  258.       // Index may be different from i when the listbox is sorted.
  259.       //
  260.       int index = AddString(listBoxData->GetStrings()[i].c_str());
  261.       SetItemData(index, listBoxData->GetItemDatas()[i]);
  262.       if (style & MULTIPLESEL) {
  263.         for (uint j = 0; j < selCount; j++)
  264.           if (listBoxData->GetSelIndices()[j] == (int)i) {
  265.             SetSel(index, true);
  266.             break;
  267.           }
  268.       }
  269.       else {
  270.         if ((uint)listBoxData->GetSelIndices()[0] == i)
  271.           selIndex = index;
  272.         else
  273.           // Inserted something before item and the item to select has been
  274.           // pushed further down in the list.
  275.           //
  276.           if (selIndex != noSelection && index <= selIndex)
  277.             selIndex++;
  278.       }
  279.     }
  280.     if (selIndex != noSelection && !(style & MULTIPLESEL))
  281.       SetSelIndex(selIndex);
  282.   }
  283.  
  284.   return sizeof(TListBoxData);
  285. }
  286.  
  287. //
  288. // Returns the index of the first string in the associated listbox
  289. // which is the same as the passed string
  290. //
  291. // Searches for a match beginning at the passed indexStart
  292. //
  293. // If a match is not found after the last string has been compared,
  294. // the search continues from the beginning of the list until a match
  295. // is found or until the list has been completely traversed
  296. //
  297. // Searches from beginning of list when -1 is passed as the index
  298. //
  299. // Returns the index of the selected string; a negative value is returned
  300. // if an error occurs
  301. //
  302. // For single or multiple-selection list boxes
  303. //
  304. int
  305. TListBox::FindExactString(const char far* findStr, int indexStart) const
  306. {
  307.   bool  found = false;
  308.   int   firstMatch = indexStart = FindString(findStr, indexStart);
  309.   do {
  310.     if (indexStart > -1) {
  311.       char*  tmpStr = new char[GetStringLen(indexStart) + 1];
  312.  
  313.       GetString(tmpStr, indexStart);
  314.  
  315.       if (strcmp(tmpStr, findStr) == 0)
  316.         found = true;
  317.  
  318.       else
  319.         indexStart = FindString(findStr, indexStart);
  320.  
  321.       delete[] tmpStr;
  322.     }
  323.   } while (!found && indexStart != firstMatch);
  324.  
  325.   return found ? indexStart : -1;
  326. }
  327.  
  328. //
  329. // For use with single-selection list boxes (and combo boxes)
  330. //
  331. // Retrieves the text of the string which is selected in the associated
  332. // listbox
  333. //
  334. // Returns the number of characters copied; -1 is returned if no string
  335. // is selected or this is a multiple-selection list box
  336. //
  337. // Since the Windows function is not passed a size parameter, we have to
  338. // allocate a string to hold the largest string (gotten from a query), and
  339. // copy a part of it
  340. //
  341. int
  342. TListBox::GetSelString(char far* str, int maxChars) const
  343. {
  344.   int  index = GetSelIndex();
  345.  
  346.   if (index > -1) {
  347.     int  length = GetStringLen(index);
  348.  
  349.     if (maxChars >= length)
  350.       return GetString(str, index);
  351.  
  352.     else {
  353.       char*  tmpStr = new char[length + 1];
  354.  
  355.       if (tmpStr) {
  356.         GetString(tmpStr, index);
  357.         strncpy(str, tmpStr, maxChars);
  358.         delete[] tmpStr;
  359.         return maxChars;
  360.       }
  361.     }
  362.   }
  363.   return -1;
  364. }
  365.  
  366. //
  367. // Returns the number of selected items in the list box. For
  368. // multiple-selection list boxes only
  369. //
  370. int
  371. TListBox::GetSelCount() const
  372. {
  373.   if (!(GetStyle() & MULTIPLESEL))
  374.     return GetSelIndex() < 0 ? 0 : 1;
  375.  
  376.   // Multiple-selection list box
  377.   //
  378.   return (int)CONST_CAST(TListBox*,this)->SendMessage(LB_GETSELCOUNT);
  379. }
  380.  
  381. //
  382. // Retrieves the text of the strings which are selected in the
  383. // associated listbox
  384. //
  385. // Returns the number of items put into Strings.  -1 is returned if this is
  386. // not a multiple-selection list box
  387. //
  388. // Since the Windows function is not passed a size parameter, we have to
  389. // allocate a string to hold the largest string (gotten from a query), and
  390. // copy a part of it
  391. //
  392. // Only for use with multiple-selection list boxes
  393. //
  394. int
  395. TListBox::GetSelStrings(char far** strs, int maxCount, int maxChars) const
  396. {
  397.   if (!(GetStyle() & MULTIPLESEL))
  398.     return -1;
  399.  
  400.   int i = GetSelCount();
  401.  
  402.   if (i < maxCount)
  403.     maxCount = i;
  404.  
  405.   if (maxCount > 0) {
  406.     int*  selections = new int[maxCount];
  407.  
  408.     GetSelIndexes(selections, maxCount);
  409.  
  410.     for (int selIndex = 0; selIndex < maxCount; selIndex++) {
  411.       int  tmpStrLen = GetStringLen(selections[selIndex]);
  412.  
  413.       if (maxChars >= tmpStrLen)
  414.         GetString(strs[selIndex], selections[selIndex]);
  415.  
  416.       else {
  417.         char*  tmpStr = new char[tmpStrLen+1];
  418.  
  419.         if (tmpStr) {
  420.           GetString(tmpStr, selections[selIndex]);
  421.           strncpy(strs[selIndex], tmpStr, maxChars);
  422.           delete[] tmpStr;
  423.         }
  424.       }
  425.     }
  426.     delete[] selections;
  427.   }
  428.   return maxCount;
  429. }
  430.  
  431. //
  432. // Selects the first string in the associated listbox following the
  433. // passed index which begins with the passed string
  434. //
  435. // Searches for a match beginning at the passed Index. if a match is not
  436. // found after the last string has been compared, the search continues
  437. // from the beginning of the list until a match is found or until the list
  438. // has been completely traversed
  439. //
  440. // Searches from beginning of list when -1 is passed as the index
  441. //
  442. // Returns the index of the selected string. a negative value is returned
  443. // if an error occurs
  444. //
  445. // Only for single-selection list boxes
  446. //
  447. int
  448. TListBox::SetSelString(const char far* findStr, int indexStart)
  449. {
  450.   if (!(GetStyle() & MULTIPLESEL))
  451.     return (int)SendMessage(LB_SELECTSTRING, indexStart, TParam2(findStr));
  452.   return -1;
  453. }
  454.  
  455. //
  456. // Selects the strings in the associated list box which begin with
  457. // the passed prefixes
  458. //
  459. // For each string the search begins at the beginning of the list
  460. // and continues until a match is found or until the list has been
  461. // completely traversed
  462. //
  463. // If ShouldSet is true, the matched strings are selected and highlighted;
  464. // otherwise the highlight is removed from the matched strings and they
  465. // are no longer selected
  466. //
  467. // Returns the number of strings successfully selected or deselected
  468. //
  469. // If NumSelections is less than zero, all strings are selected or deselected
  470. // and a negative value is returned on failure
  471. //
  472. // Only for multiple-selection list boxes (-1 is returned if this is not
  473. // a multiple-selection list box)
  474. //
  475. int
  476. TListBox::SetSelStrings(const char far** strs, int numSelections, bool shouldSet)
  477. {
  478.   if (!(GetStyle() & MULTIPLESEL))
  479.     return -1;
  480.  
  481.   if (numSelections < 0)
  482.     return SetSel(-1, shouldSet);
  483.  
  484.   int  successes = 0;
  485.   for (int i = 0; i < numSelections; i++) {
  486.     int  selIndex;
  487.     if ((selIndex = FindString(strs[i], -1)) > -1)
  488.       if (SetSel(selIndex, shouldSet) > -1)
  489.         successes++;
  490.   }
  491.   return successes;
  492. }
  493.  
  494. //
  495. // Returns the index of the selected string in the associated listbox
  496. //
  497. // A negative value is returned if no string is selected or this
  498. // is a multiple-selection list box
  499. //
  500. // Only for single-selection list boxes
  501. //
  502. int
  503. TListBox::GetSelIndex() const
  504. {
  505.   if (!(GetStyle() & MULTIPLESEL))
  506.     return (int)CONST_CAST(TListBox*,this)->SendMessage(LB_GETCURSEL);
  507.   return -1;
  508. }
  509.  
  510. //
  511. // Fills indexes with the indexes of up to maxCount selected strings
  512. //
  513. // Returns number of items put in the array (-1 for single-selection
  514. // list boxes)
  515. //
  516. int
  517. TListBox::GetSelIndexes(int* indexes, int maxCount) const
  518. {
  519.   if (!(GetStyle() & MULTIPLESEL))
  520.     return -1;
  521.   return (int)CONST_CAST(TListBox*,this)->SendMessage(LB_GETSELITEMS,
  522.                                                         maxCount,
  523.                                                         TParam2(indexes));
  524. }
  525.  
  526. // Selects the string at passed index in the associated listbox and
  527. // forces the string into view
  528. //
  529. // Clears selection when -1 is passed as the index. a negative value is
  530. // returned if an error occurs
  531. //
  532. // Only for single-selection list boxes
  533. //
  534. int
  535. TListBox::SetSelIndex(int index)
  536. {
  537.   if (!(GetStyle() & MULTIPLESEL))
  538.     return (int)SendMessage(LB_SETCURSEL, index);
  539.   return -1;
  540. }
  541.  
  542. //
  543. // Selects/deselects the strings in the associated list box at the
  544. // passed indexes
  545. //
  546. // If ShouldSet is true, the indexed strings are selected and highlighted;
  547. // otherwise the highlight is removed and they are no longer selected
  548. //
  549. // Returns the number of strings successfully selected or deselected(-1
  550. // if not a multiple-selection list box)
  551. //
  552. // If NumSelections is less than zero, all strings are selected or deselected
  553. // and a negative value is returned on failure
  554. //
  555. // only for multiple-selection list boxes
  556. //
  557. int
  558. TListBox::SetSelIndexes(int* indexes, int numSelections, bool shouldSet)
  559. {
  560.   int  successes = 0;
  561.  
  562.   if (!(GetStyle() & MULTIPLESEL))
  563.     return -1;  // including if it's a combobox
  564.  
  565.   if (numSelections < 0)
  566.     return (int)SendMessage(LB_SETSEL, shouldSet, -1);
  567.  
  568.   else {
  569.     for (int i = 0; i < numSelections; i++)
  570.       if ((int)SendMessage(LB_SETSEL, shouldSet, indexes[i]) > -1)
  571.         successes++;
  572.   }
  573.   return successes;
  574. }
  575.  
  576. #endif
  577. #if !defined(SECTION) || SECTION == 2
  578.  
  579. IMPLEMENT_STREAMABLE1(TListBox, TControl);
  580.  
  581. #if !defined(BI_NO_OBJ_STREAMING)
  582.  
  583. //
  584. // Reads an instance of TListBox from the supplied ipstream
  585. //
  586. void*
  587. TListBox::Streamer::Read(ipstream& is, uint32 /*version*/) const
  588. {
  589.   ReadBaseObject((TControl*)GetObject(), is);
  590.   return GetObject();
  591. }
  592.  
  593. //
  594. // Writes the TListBox to the supplied opstream
  595. //
  596. void
  597. TListBox::Streamer::Write(opstream& os) const
  598. {
  599.   WriteBaseObject((TControl*)GetObject(), os);
  600. }
  601.  
  602. #endif  // if !defined(BI_NO_OBJ_STREAMING)
  603.  
  604. #endif
  605.  
  606.